#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QScreen>
#include <QFileDialog>
#include <QProgressDialog>
#include <QHash>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 不允许调整窗口大小
    setWindowFlags(windowFlags()& ~Qt::WindowMaximizeButtonHint);
    setFixedSize(this->width(), this->height());
    // 窗口显示在屏幕正中
    QScreen *screen = QGuiApplication::primaryScreen();
    move((screen->geometry().width() - this->width()) / 2, (screen->geometry().height() - this->height()) / 2);

    GDALAllRegister();
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButtonIn_clicked()
{
    QString gdbPath = QFileDialog::getExistingDirectory();
    ui->lineEditIn->setText(gdbPath);
    if (gdbPath.isEmpty())
    {
        initInControls();
        return;
    }

    GDALDataset *inDs = static_cast<GDALDataset*>(GDALOpenEx(gdbPath.toStdString().c_str(), GDAL_OF_VECTOR, NULL, NULL, NULL ));
    if(inDs == nullptr)
    {
        msgBox.critical(this, "文件错误", "请选择正确的gdb路径");
        initInControls();
        return;
    }

    for (int i = 0; i < inDs->GetLayerCount(); i++)
    {
        OGRLayer *layer = inDs->GetLayer(i);
        QString name(layer->GetName());
        ui->comboBoxLayer->addItem(name);
    }
    GDALClose(inDs);
}


void MainWindow::on_pushButtonOut_clicked()
{
    ui->lineEditOut->setText(QFileDialog::getSaveFileName(this, QString(), QString(), "GeoPackage(*.gpkg)"));
}


void MainWindow::on_pushButtonOk_clicked()
{
    ui->pushButtonOk->setDisabled(true);

    // 校验文件
    QString inPath = ui->lineEditIn->text();
    QString outPath = ui->lineEditOut->text();
    if (inPath.isEmpty())
    {
        msgBox.critical(this, "路径错误", "请选择FileGDB");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (outPath.isEmpty())
    {
        msgBox.critical(this, "路径错误", "请选择GeoPackage");
        ui->pushButtonOk->setDisabled(false);
        return;
    }

    // 开始读取
    GDALDataset *inDs = static_cast<GDALDataset*>(GDALOpenEx(inPath.toStdString().c_str(), GDAL_OF_VECTOR, NULL, NULL, NULL ));
    OGRLayer *layer = inDs->GetLayerByName(ui->comboBoxLayer->currentText().toStdString().c_str());
    OGRSpatialReference *sr = layer->GetSpatialRef();

    // 校验字段
    OGRFeatureDefn *defn = layer->GetLayerDefn();
    if (defn->GetFieldIndex("altitude_low") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含altitude_low字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("altitude_upper") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含altitude_upper字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h1") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h1字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h2") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h2字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h3") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h3字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h4") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h4字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h5") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h5字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h6") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h6字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h7") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h7字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }
    if (defn->GetFieldIndex("h8") < 0)
    {
        msgBox.critical(this, "数据错误", "所选图层未包含h8字段");
        ui->pushButtonOk->setDisabled(false);
        return;
    }

    // 初始化进度条
    int totalNum = layer->GetFeatureCount();
    QProgressDialog proDialog("正在转换", "取消", 0, totalNum, this);
    proDialog.setModal(true);
    proDialog.setWindowTitle("转换进度");
    proDialog.setValue(0);
    proDialog.show();

    // 创建输出文件
    GDALDriver *driver = GetGDALDriverManager()->GetDriverByName("GPKG");
    GDALDataset *outDs = driver->Create(outPath.toStdString().c_str(), 0, 0, 0, GDT_Unknown, NULL);

    // 逐条记录处理
    layer->ResetReading();
    OGRFeature *feature;
    int i = 0;
    QHash<OGRwkbGeometryType, OGRLayer*> layerMap;
    while((feature = layer->GetNextFeature()) != NULL)
    {
        OGRGeometry *geometry = feature->GetGeometryRef();
        OGRwkbGeometryType typeCode = geometry->getGeometryType();
        if (!layerMap.contains(typeCode)) // 为新类型创建图层
        {
            layerMap.insert(typeCode, createLayer(outDs, geometry->getGeometryName(), sr, typeCode));
        }
        // 复制feature
        OGRLayer *newLayer = layerMap.find(typeCode).value();
        OGRFeature *newFeature = OGRFeature::CreateFeature(newLayer->GetLayerDefn());
        newFeature->SetGeometry(geometry);
        copyField(feature, newFeature, "altitude_low");
        copyField(feature, newFeature, "altitude_upper");
        copyField(feature, newFeature, "h1");
        copyField(feature, newFeature, "h2");
        copyField(feature, newFeature, "h3");
        copyField(feature, newFeature, "h4");
        copyField(feature, newFeature, "h5");
        copyField(feature, newFeature, "h6");
        copyField(feature, newFeature, "h7");
        copyField(feature, newFeature, "h8");
        newLayer->CreateFeature(newFeature);

        OGRFeature::DestroyFeature(newFeature);
        OGRFeature::DestroyFeature(feature);

        proDialog.setValue(i);
        QCoreApplication::processEvents();
        if (proDialog.wasCanceled())
        {
            GDALClose(outDs);
            GDALClose(inDs);
            ui->pushButtonOk->setDisabled(false);
            return;
        }
        i++;
    }

    GDALClose(outDs);
    GDALClose(inDs);
    proDialog.setValue(totalNum); // 到达最大值，自动关闭
    msgBox.information(this, "转换完成", "转换完成");
    this->close();
}


void MainWindow::on_pushButtonCancel_clicked()
{
    this->close();
}

void MainWindow::initInControls()
{
    ui->lineEditIn->setText("");
    ui->comboBoxLayer->clear();
}

OGRLayer *MainWindow::createLayer(GDALDataset *outDs, const char* layerName, OGRSpatialReference *sr, OGRwkbGeometryType geomType)
{
    OGRLayer *layer = outDs->CreateLayer(layerName, sr, geomType, NULL);
    OGRFieldDefn fieldALow("altitude_low", OFTInteger);
    OGRFieldDefn fieldAUpper("altitude_upper", OFTInteger);
    OGRFieldDefn fieldH1("h1", OFTInteger);
    OGRFieldDefn fieldH2("h2", OFTInteger);
    OGRFieldDefn fieldH3("h3", OFTInteger);
    OGRFieldDefn fieldH4("h4", OFTInteger);
    OGRFieldDefn fieldH5("h5", OFTInteger);
    OGRFieldDefn fieldH6("h6", OFTInteger);
    OGRFieldDefn fieldH7("h7", OFTInteger);
    OGRFieldDefn fieldH8("h8", OFTInteger);
    layer->CreateField(&fieldALow);
    layer->CreateField(&fieldAUpper);
    layer->CreateField(&fieldH1);
    layer->CreateField(&fieldH2);
    layer->CreateField(&fieldH3);
    layer->CreateField(&fieldH4);
    layer->CreateField(&fieldH5);
    layer->CreateField(&fieldH6);
    layer->CreateField(&fieldH7);
    layer->CreateField(&fieldH8);
    return layer;
}

bool MainWindow::copyField(OGRFeature *feature, OGRFeature *newFeature, const char *fieldName)
{
    if (feature->IsFieldNull(feature->GetFieldIndex(fieldName)))
    {
        return false;
    }

    newFeature->SetField(fieldName, feature->GetFieldAsInteger(fieldName));
    return true;
}

